package me.fung.wubi.base.define.table

import me.fung.wubi.base.define.value.Code
import me.fung.wubi.base.define.value.Word
import me.fung.wubi.base.define.value.WordFrequency
import java.util.LinkedList

class CodeItem(
    val code: Code,
    private val _words: MutableList<Word> = LinkedList()
) : List<Word> by _words {
    fun isNotEmpty(): Boolean = !isEmpty()
    private val lock: Any = Any()
    fun add(word: Word): Unit = synchronized(lock) {
        _words.remove(word)
        _words.add(word)
    }


    fun remove(word: Word) = synchronized(lock) {
        _words.remove(word)
    }


    fun addCodeItem(codeItem: CodeItem) {
        if (codeItem.code != code) return
        codeItem.forEach(::add)
    }

    fun wordSize(): Int {
        return _words.size
    }

    fun clone(filter: (Word) -> Boolean): CodeItem {
        val item = CodeItem(code)
        forEach {
            if (filter(it)) {
                item.add(it)
            }
        }
        return item
    }

    fun like(value: String): Boolean {
        forEach {
            if (it.value.contains(value)) {
                return true
            }
        }
        return false
    }

    fun sortByFreq(wf: WordFrequency) {
        if (size < 1) return
        val l = map {
            it to wf.frequencyOf(it)
        }.sortedBy {
            -it.second
        }.mapTo(ArrayList()) {
            it.first
        }
        val ci = CodeItem(code,l)
        replaceAll(ci)
    }

    override fun toString(): String {
        return "[$code : ${_words.joinToString(",")}]"
    }

    fun Word.hasPrevious(): Boolean {
        val index = _words.indexOf(this)
        return index > 0
    }

    fun replaceAll(item: CodeItem) {
        if (code != item.code) return
        _words.clear()
        addCodeItem(item)
    }

    fun Word.moveToPrevious() {
        if (!hasPrevious()) return
        synchronized(lock) {
            val index = _words.indexOf(this)
            val indexTo = index - 1
            val word = _words[indexTo]
            _words[indexTo] = this
            _words[index] = word
        }
    }

    fun Word.hasNext(): Boolean {
        val index = _words.indexOf(this)
        return index < _words.size - 1
    }

    fun Word.moveToNext() {
        if (!hasNext()) return
        synchronized(lock) {
            val index = _words.indexOf(this)
            val indexTo = index + 1
            val word = _words[indexTo]
            _words[indexTo] = this
            _words[index] = word
        }
    }
}
